#!/usr/bin/python

import os
import os.path
import optparse
import sys
import signal
import time
import ConfigParser
import system.core.globals as sys_globals

from optparse import OptionParser
from application import SchedulerApplication
from process import daemonize, launch_scheduler_process, launch_logger_process 


signal_child_event = 0
signal_exit_event  = 0


"""
class       : OptionArgs
description : class which store value for option argument
"""

class OptionArgs(object):

    """
    config: config file path
    """
    config = ''

    """
    debug: debug mode
    """
    debug = False

    def __init__(self):
        super(OptionArgs, self).__init__()


"""
signal handler
"""
def handler(signum, frame):
    global signal_child_event
    global signal_exit_event

    if signum in [signal.SIGTERM, signal.SIGSTOP]:
        signal_exit_event = 1
        return
    if signum in [signal.SIGCHLD]:
        signal_child_event = 1
        return


"""
write pid file
"""
def write_pid_file(pid_file):
    result = True
    fp = None
    try:
        fp = open(pid_file, "w")
        fp.write(str(os.getpid()))
    except Exception,e:
        result = False
    finally:
        if fp is not None:
            fp.close()
    return result


"""
main: main function for procedure
"""
def main():
    """
    Parser input arguments
    """
    if len(sys.argv) <= 1:
        print ("[Main][ERROR] No input argument for starting command.")
        sys.exit(-1)


    option_args = None
    try:
        option_args = OptionArgs()
        arg_parser = OptionParser(prog="scheduler", description="scheduler plugin for integrated system")
        arg_parser.add_option("-c", "--config", default='', help="set scheduler config file path")
        arg_parser.add_option("-v", "--debug", action="store_true", default=False, help="set debug mode")
        arg_parser.parse_args(sys.argv[1:], option_args)
    except optparse.OptionError,e:
        print ("[Main][ERROR] parse command line failure.")
        sys.exit(-1)

    """
    Get and judge config file is available
    """
    if option_args.config == '':
        print ("Main][ERROR] config file of scheudler must specified.")
        sys.exit(-1)
    elif not os.path.exists(option_args.config):
        print ("[Main][ERROR] config file %s can not be found" % (option_args.config))
        sys.exit(-1)
    else:
        if os.path.dirname(option_args.config) == '':
            option_args.config = os.getcwd() + "/" + option_args.config
        sys_globals.configuration_file = option_args.config

    """
    List configuration variable
    """
    interval_check = 0
    log_file_path  = ''
    logger_sock    = ''
    max_worker     = 0
    pid_file       = ''

    """
    Read configuration file and make arguments judgement
    """
    configuration = dict()
    try:
        cfgParser = ConfigParser.ConfigParser()
        cfgParser.read(option_args.config)
        interval_check = cfgParser.getint('server', 'interval_check')
        log_file_path  = cfgParser.get('server',    'log_file_path')
        logger_sock    = cfgParser.get('server',    'logger_sock')
        max_worker     = cfgParser.getint('server', 'max_worker')
        pid_file       = cfgParser.get('server',    'pid_file')
    except ConfigParser.Error,e:
        print ("[Main][ERROR] parser file error, message: %s" % (str(e)))
        sys.exit(-1)

    if option_args.debug == False:
        """
        Fork Process
        """
        pid = -1
        try:
            pid = os.fork()
            if pid > 0:
                #print ("[Main Process PID %d] Exit Program......" % (os.getpid()))
                sys.exit(0)
        except OSError,e:
            print ("[Main][ERROR] Fork process failure, message: %s" % (str(e)))
            sys.exit(-1)

        os.umask(0)
        os.setuid(os.getuid())
        os.setsid()
        os.dup2(sys.stderr.fileno(), sys.stdin.fileno())
        os.close(sys.stdin.fileno())
        os.close(sys.stderr.fileno())    

    """
    test pid file, log file, log socket path and some variabels
    """
    if not os.path.exists(os.path.dirname(log_file_path)):
        print("[Main][Error] Can not write log file '%s', please check if directory is exist." % (log_file_path))
        sys.exit(-1)

    if not os.path.exists(os.path.dirname(logger_sock)):
        print("[Main][Error] Can not create logger socket file '%s', please check if directoy is exist." % (logger_sock))
        sys.exit(-1)

    if not os.path.exists(os.path.dirname(pid_file)):
        print ("[Main][Error] Can not write pid file '%s', please check if directory is exist." % (pid_file))
        sys.exit(-1)
    else:
        if os.path.exists(pid_file):
            print("[Main][Error] Process already running, do not try to start it again.");
            sys.exit(-1)
        if not write_pid_file(pid_file):
            print("[Main][Error] Can not write pid file '%s', Maybe IO Error occured." % (pid_file))
            sys.exit(-1)

    if interval_check < 0:
        print("[Main][Error] Variable 'interval' must largger than 0");
        sys.exit(-1)

    if max_worker < 0  or max_worker > 100:
        print("[Main][Error] Variable 'max_worker' must be largger than 0 and less than 101")
        sys.exit(-1)

    """
    regroup process variable
    """
    logger_configuration                = dict()
    logger_configuration['logger_sock'] = logger_sock

    scheduler_configuration                   = dict()
    scheduler_configuration['interval_check'] = interval_check
    scheduler_configuration['max_worker']     = max_worker

    """
    Set Tast List
    """
    processList = list()
    processList.append({"process":launch_logger_process, "kwargs":logger_configuration, "pid":-1})
    processList.append({"process":launch_scheduler_process, "kwargs":scheduler_configuration, "pid":-1})

    try:
        for i in xrange(0, len(processList)):
            processList[i]["pid"] = daemonize(processList[i]["process"], **(processList[i]["kwargs"]))
    except Exception,e:
        print (str(e))
        sys.exit(-1)

    global signal_child_event
    global signal_exit_event
    signal_child_event = 0
    signal_exit_event  = 0
    signal.signal(signal.SIGTERM, handler)
    signal.signal(signal.SIGCHLD, handler)

    try:
        nprocess = len(processList)
        while True:
            """
            If exit signal is ready
            """
            if signal_exit_event == 1:
                for i in xrange(0, nprocess):
                    os.kill(processList[i]['pid'], signal.SIGKILL)
                signal_exit_event = 0
                os.unlink(pid_file)
                os.unlink(logger_sock)
                break
            """
            If child exit signal is ready
            """
            if signal_child_event == 1:
                signal_child_event = 0
                pid, status = os.waitpid(0, os.WNOHANG)
                for i in xrange(0, nprocess):
                    if pid == processList[i]["pid"]:
                        processList[i]['pid'] = daemonize(processList[i]["process"], **(processList[i]["kwargs"]))
                        break
            time.sleep(2)
    except OSError,e:
        print (str(e))
        sys.exit(-1)
    print ("[Main]Exit Program......")
    sys.exit(0) 


if __name__ == "__main__":
    main()
